package com.ygl.strategy.adapter;

import com.netflix.loadbalancer.Server;
import com.ygl.common.constant.DiscoveryConstant;
import com.ygl.common.util.JsonUtil;
import com.ygl.common.util.StringUtil;
import com.ygl.core.adapter.CoreAdapter;
import com.ygl.core.context.CoreContextHolder;
import com.ygl.strategy.matcher.DiscoveryMatcherStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Map;

/**
 * author: yanggld
 * date: 2019/12/21 21:21
 * version: 1.0
 * description: DefaultDiscoveryEnabledAdapter
 */
@Slf4j
public class DefaultDiscoveryEnabledAdapter implements  DiscoveryEnabledAdapter {

    @Autowired(required = false)
    private DiscoveryEnabledStrategy discoveryEnabledStrategy;
    @Autowired
    private DiscoveryMatcherStrategy discoveryMatcherStrategy;
    @Autowired
    protected CoreContextHolder coreContextHolder;
    @Autowired
    protected CoreAdapter coreAdapter;

    @Override
    public boolean apply(Server server) {
        boolean enabled = applyVersion(server);
        if (!enabled) {
            String serverServiceId = coreAdapter.getServerServiceId(server);
            log.warn("服务{"+serverServiceId+" [ "+server.getHostPort()+" ]}版本策略未通过");
            return false;
        }
        enabled = applyRegion(server);
        if (!enabled) {
            String serverServiceId = coreAdapter.getServerServiceId(server);
            log.warn("服务{"+serverServiceId+" [ "+server.getHostPort()+" ]}区域策略未通过");
            return false;
        }
        enabled = applyStrategy(server);
        if (enabled) {
            String serverServiceId = coreAdapter.getServerServiceId(server);
            log.warn("服务{"+serverServiceId+" [ "+server.getHostPort()+" ]}通过策略");
        }
        return enabled;
    }

    private boolean applyVersion(Server server) {
        String versionValue = coreContextHolder.getContextRouteVersion();
        if (StringUtils.isEmpty(versionValue)) {
            return true;
        }

        String serviceId = coreAdapter.getServerServiceId(server);
        String version = coreAdapter.getServerVersion(server);

        String versions = null;
        try {
            Map<String, String> versionMap = JsonUtil.fromJson(versionValue, Map.class);
            versions = versionMap.get(serviceId);
        } catch (Exception e) {
            versions = versionValue;
        }

        if (StringUtils.isEmpty(versions)) {
            return true;
        }

        // 如果精确匹配不满足，尝试用通配符匹配
        List<String> versionList = StringUtil.splitToList(versions, DiscoveryConstant.SEPARATE);
        if (versionList.contains(version)) {
            return true;
        }

        // 通配符匹配。前者是通配表达式，后者是具体值
        for (String versionPattern : versionList) {
            if (discoveryMatcherStrategy.match(versionPattern, version)) {
                return true;
            }
        }

        return false;
    }

    private boolean applyRegion(Server server) {
        String regionValue = coreContextHolder.getContextRouteRegion();
        if (StringUtils.isEmpty(regionValue)) {
            return true;
        }

        String serviceId = coreAdapter.getServerServiceId(server);
        String region = coreAdapter.getServerRegion(server);

        String regions = null;
        try {
            Map<String, String> regionMap = JsonUtil.fromJson(regionValue, Map.class);
            regions = regionMap.get(serviceId);
        } catch (Exception e) {
            regions = regionValue;
        }

        if (StringUtils.isEmpty(regions)) {
            return true;
        }

        // 如果精确匹配不满足，尝试用通配符匹配
        List<String> regionList = StringUtil.splitToList(regions, DiscoveryConstant.SEPARATE);
        if (regionList.contains(region)) {
            return true;
        }

        // 通配符匹配。前者是通配表达式，后者是具体值
        for (String regionPattern : regionList) {
            if (discoveryMatcherStrategy.match(regionPattern, region)) {
                return true;
            }
        }

        return false;
    }


    private boolean applyStrategy(Server server) {
        if (discoveryEnabledStrategy == null) {
            return true;
        }
        return discoveryEnabledStrategy.apply(server);
    }


}
